
Student: Márquez Delgado Esteban
Registry: if700637
This document was prepared by Esteban Márquez Delgado as delivery for Laboratory 1 of Microstructure and Trading Systems - MAF1731B class during the Autumn 2022 course at ITESO for the Bachelor of Financial Engineering.
Note: To run this notebook it is necessary to have the following libraries contained in the requirements.txt script of this project.
To install the libraries in the script run the following cell:
!pip install -r requirements.txt
Requirement already satisfied: pandas>=1.3.4 in c:\programdata\anaconda3\lib\site-packages (from -r requirements.txt (line 10)) (1.4.2) Requirement already satisfied: numpy>=1.19.1 in c:\programdata\anaconda3\lib\site-packages (from -r requirements.txt (line 11)) (1.21.5) Requirement already satisfied: jupyter>=1.0.0 in c:\programdata\anaconda3\lib\site-packages (from -r requirements.txt (line 12)) (1.0.0) Requirement already satisfied: chart_studio>=1.1 in c:\programdata\anaconda3\lib\site-packages (from -r requirements.txt (line 13)) (1.1.0) Requirement already satisfied: plotly>=4.14 in c:\programdata\anaconda3\lib\site-packages (from -r requirements.txt (line 14)) (5.6.0) Requirement already satisfied: pandas_datareader>=0.10.0 in c:\programdata\anaconda3\lib\site-packages (from -r requirements.txt (line 15)) (0.10.0) Requirement already satisfied: tk>=0.1.0 in c:\programdata\anaconda3\lib\site-packages (from -r requirements.txt (line 16)) (0.1.0) Requirement already satisfied: yahoofinancials>=1.6 in c:\programdata\anaconda3\lib\site-packages (from -r requirements.txt (line 18)) (1.6) Requirement already satisfied: scipy>=1.7.3 in c:\programdata\anaconda3\lib\site-packages (from -r requirements.txt (line 19)) (1.7.3) Requirement already satisfied: regex>=2022.3.15 in c:\programdata\anaconda3\lib\site-packages (from -r requirements.txt (line 20)) (2022.3.15) Requirement already satisfied: matplotlib>=3.5.1 in c:\programdata\anaconda3\lib\site-packages (from -r requirements.txt (line 21)) (3.5.1) Requirement already satisfied: fire>=0.4.0 in c:\programdata\anaconda3\lib\site-packages (from -r requirements.txt (line 22)) (0.4.0) Requirement already satisfied: pytz>=2020.1 in c:\programdata\anaconda3\lib\site-packages (from pandas>=1.3.4->-r requirements.txt (line 10)) (2021.3) Requirement already satisfied: python-dateutil>=2.8.1 in c:\programdata\anaconda3\lib\site-packages (from pandas>=1.3.4->-r requirements.txt (line 10)) (2.8.2) Requirement already satisfied: notebook in c:\programdata\anaconda3\lib\site-packages (from jupyter>=1.0.0->-r requirements.txt (line 12)) (6.4.8) Requirement already satisfied: ipywidgets in c:\programdata\anaconda3\lib\site-packages (from jupyter>=1.0.0->-r requirements.txt (line 12)) (7.6.5) Requirement already satisfied: qtconsole in c:\programdata\anaconda3\lib\site-packages (from jupyter>=1.0.0->-r requirements.txt (line 12)) (5.3.0) Requirement already satisfied: jupyter-console in c:\programdata\anaconda3\lib\site-packages (from jupyter>=1.0.0->-r requirements.txt (line 12)) (6.4.0) Requirement already satisfied: ipykernel in c:\programdata\anaconda3\lib\site-packages (from jupyter>=1.0.0->-r requirements.txt (line 12)) (6.9.1) Requirement already satisfied: nbconvert in c:\programdata\anaconda3\lib\site-packages (from jupyter>=1.0.0->-r requirements.txt (line 12)) (6.4.4) Requirement already satisfied: retrying>=1.3.3 in c:\programdata\anaconda3\lib\site-packages (from chart_studio>=1.1->-r requirements.txt (line 13)) (1.3.3) Requirement already satisfied: six in c:\programdata\anaconda3\lib\site-packages (from chart_studio>=1.1->-r requirements.txt (line 13)) (1.16.0) Requirement already satisfied: requests in c:\programdata\anaconda3\lib\site-packages (from chart_studio>=1.1->-r requirements.txt (line 13)) (2.27.1) Requirement already satisfied: tenacity>=6.2.0 in c:\programdata\anaconda3\lib\site-packages (from plotly>=4.14->-r requirements.txt (line 14)) (8.0.1) Requirement already satisfied: lxml in c:\programdata\anaconda3\lib\site-packages (from pandas_datareader>=0.10.0->-r requirements.txt (line 15)) (4.8.0) Requirement already satisfied: beautifulsoup4 in c:\programdata\anaconda3\lib\site-packages (from yahoofinancials>=1.6->-r requirements.txt (line 18)) (4.11.1) Requirement already satisfied: pyparsing>=2.2.1 in c:\programdata\anaconda3\lib\site-packages (from matplotlib>=3.5.1->-r requirements.txt (line 21)) (3.0.4) Requirement already satisfied: fonttools>=4.22.0 in c:\programdata\anaconda3\lib\site-packages (from matplotlib>=3.5.1->-r requirements.txt (line 21)) (4.25.0) Requirement already satisfied: cycler>=0.10 in c:\programdata\anaconda3\lib\site-packages (from matplotlib>=3.5.1->-r requirements.txt (line 21)) (0.11.0) Requirement already satisfied: kiwisolver>=1.0.1 in c:\programdata\anaconda3\lib\site-packages (from matplotlib>=3.5.1->-r requirements.txt (line 21)) (1.3.2) Requirement already satisfied: pillow>=6.2.0 in c:\programdata\anaconda3\lib\site-packages (from matplotlib>=3.5.1->-r requirements.txt (line 21)) (9.0.1) Requirement already satisfied: packaging>=20.0 in c:\programdata\anaconda3\lib\site-packages (from matplotlib>=3.5.1->-r requirements.txt (line 21)) (21.3) Requirement already satisfied: termcolor in c:\programdata\anaconda3\lib\site-packages (from fire>=0.4.0->-r requirements.txt (line 22)) (1.1.0) Requirement already satisfied: idna<4,>=2.5 in c:\programdata\anaconda3\lib\site-packages (from requests->chart_studio>=1.1->-r requirements.txt (line 13)) (3.3) Requirement already satisfied: urllib3<1.27,>=1.21.1 in c:\programdata\anaconda3\lib\site-packages (from requests->chart_studio>=1.1->-r requirements.txt (line 13)) (1.26.9) Requirement already satisfied: certifi>=2017.4.17 in c:\programdata\anaconda3\lib\site-packages (from requests->chart_studio>=1.1->-r requirements.txt (line 13)) (2021.10.8) Requirement already satisfied: charset-normalizer~=2.0.0 in c:\programdata\anaconda3\lib\site-packages (from requests->chart_studio>=1.1->-r requirements.txt (line 13)) (2.0.4) Requirement already satisfied: soupsieve>1.2 in c:\programdata\anaconda3\lib\site-packages (from beautifulsoup4->yahoofinancials>=1.6->-r requirements.txt (line 18)) (2.3.1) Requirement already satisfied: matplotlib-inline<0.2.0,>=0.1.0 in c:\programdata\anaconda3\lib\site-packages (from ipykernel->jupyter>=1.0.0->-r requirements.txt (line 12)) (0.1.2) Requirement already satisfied: tornado<7.0,>=4.2 in c:\programdata\anaconda3\lib\site-packages (from ipykernel->jupyter>=1.0.0->-r requirements.txt (line 12)) (6.1) Requirement already satisfied: nest-asyncio in c:\programdata\anaconda3\lib\site-packages (from ipykernel->jupyter>=1.0.0->-r requirements.txt (line 12)) (1.5.5) Requirement already satisfied: traitlets<6.0,>=5.1.0 in c:\programdata\anaconda3\lib\site-packages (from ipykernel->jupyter>=1.0.0->-r requirements.txt (line 12)) (5.1.1) Requirement already satisfied: ipython>=7.23.1 in c:\programdata\anaconda3\lib\site-packages (from ipykernel->jupyter>=1.0.0->-r requirements.txt (line 12)) (8.2.0) Requirement already satisfied: jupyter-client<8.0 in c:\programdata\anaconda3\lib\site-packages (from ipykernel->jupyter>=1.0.0->-r requirements.txt (line 12)) (6.1.12) Requirement already satisfied: debugpy<2.0,>=1.0.0 in c:\programdata\anaconda3\lib\site-packages (from ipykernel->jupyter>=1.0.0->-r requirements.txt (line 12)) (1.5.1) Requirement already satisfied: pygments>=2.4.0 in c:\programdata\anaconda3\lib\site-packages (from ipython>=7.23.1->ipykernel->jupyter>=1.0.0->-r requirements.txt (line 12)) (2.11.2) Requirement already satisfied: backcall in c:\programdata\anaconda3\lib\site-packages (from ipython>=7.23.1->ipykernel->jupyter>=1.0.0->-r requirements.txt (line 12)) (0.2.0) Requirement already satisfied: setuptools>=18.5 in c:\programdata\anaconda3\lib\site-packages (from ipython>=7.23.1->ipykernel->jupyter>=1.0.0->-r requirements.txt (line 12)) (61.2.0) Requirement already satisfied: decorator in c:\programdata\anaconda3\lib\site-packages (from ipython>=7.23.1->ipykernel->jupyter>=1.0.0->-r requirements.txt (line 12)) (5.1.1) Requirement already satisfied: pickleshare in c:\programdata\anaconda3\lib\site-packages (from ipython>=7.23.1->ipykernel->jupyter>=1.0.0->-r requirements.txt (line 12)) (0.7.5) Requirement already satisfied: prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0 in c:\programdata\anaconda3\lib\site-packages (from ipython>=7.23.1->ipykernel->jupyter>=1.0.0->-r requirements.txt (line 12)) (3.0.20) Requirement already satisfied: jedi>=0.16 in c:\programdata\anaconda3\lib\site-packages (from ipython>=7.23.1->ipykernel->jupyter>=1.0.0->-r requirements.txt (line 12)) (0.18.1) Requirement already satisfied: stack-data in c:\programdata\anaconda3\lib\site-packages (from ipython>=7.23.1->ipykernel->jupyter>=1.0.0->-r requirements.txt (line 12)) (0.2.0) Requirement already satisfied: colorama in c:\programdata\anaconda3\lib\site-packages (from ipython>=7.23.1->ipykernel->jupyter>=1.0.0->-r requirements.txt (line 12)) (0.4.4) Requirement already satisfied: parso<0.9.0,>=0.8.0 in c:\programdata\anaconda3\lib\site-packages (from jedi>=0.16->ipython>=7.23.1->ipykernel->jupyter>=1.0.0->-r requirements.txt (line 12)) (0.8.3) Requirement already satisfied: jupyter-core>=4.6.0 in c:\programdata\anaconda3\lib\site-packages (from jupyter-client<8.0->ipykernel->jupyter>=1.0.0->-r requirements.txt (line 12)) (4.9.2) Requirement already satisfied: pyzmq>=13 in c:\programdata\anaconda3\lib\site-packages (from jupyter-client<8.0->ipykernel->jupyter>=1.0.0->-r requirements.txt (line 12)) (22.3.0) Requirement already satisfied: pywin32>=1.0 in c:\programdata\anaconda3\lib\site-packages (from jupyter-core>=4.6.0->jupyter-client<8.0->ipykernel->jupyter>=1.0.0->-r requirements.txt (line 12)) (302) Requirement already satisfied: wcwidth in c:\programdata\anaconda3\lib\site-packages (from prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0->ipython>=7.23.1->ipykernel->jupyter>=1.0.0->-r requirements.txt (line 12)) (0.2.5) Requirement already satisfied: jupyterlab-widgets>=1.0.0 in c:\programdata\anaconda3\lib\site-packages (from ipywidgets->jupyter>=1.0.0->-r requirements.txt (line 12)) (1.0.0) Requirement already satisfied: nbformat>=4.2.0 in c:\programdata\anaconda3\lib\site-packages (from ipywidgets->jupyter>=1.0.0->-r requirements.txt (line 12)) (5.3.0) Requirement already satisfied: ipython-genutils~=0.2.0 in c:\programdata\anaconda3\lib\site-packages (from ipywidgets->jupyter>=1.0.0->-r requirements.txt (line 12)) (0.2.0) Requirement already satisfied: widgetsnbextension~=3.5.0 in c:\programdata\anaconda3\lib\site-packages (from ipywidgets->jupyter>=1.0.0->-r requirements.txt (line 12)) (3.5.2) Requirement already satisfied: fastjsonschema in c:\programdata\anaconda3\lib\site-packages (from nbformat>=4.2.0->ipywidgets->jupyter>=1.0.0->-r requirements.txt (line 12)) (2.15.1) Requirement already satisfied: jsonschema>=2.6 in c:\programdata\anaconda3\lib\site-packages (from nbformat>=4.2.0->ipywidgets->jupyter>=1.0.0->-r requirements.txt (line 12)) (4.4.0) Requirement already satisfied: importlib-resources>=1.4.0 in c:\programdata\anaconda3\lib\site-packages (from jsonschema>=2.6->nbformat>=4.2.0->ipywidgets->jupyter>=1.0.0->-r requirements.txt (line 12)) (5.2.0) Requirement already satisfied: pyrsistent!=0.17.0,!=0.17.1,!=0.17.2,>=0.14.0 in c:\programdata\anaconda3\lib\site-packages (from jsonschema>=2.6->nbformat>=4.2.0->ipywidgets->jupyter>=1.0.0->-r requirements.txt (line 12)) (0.18.0) Requirement already satisfied: attrs>=17.4.0 in c:\programdata\anaconda3\lib\site-packages (from jsonschema>=2.6->nbformat>=4.2.0->ipywidgets->jupyter>=1.0.0->-r requirements.txt (line 12)) (21.4.0) Requirement already satisfied: zipp>=3.1.0 in c:\programdata\anaconda3\lib\site-packages (from importlib-resources>=1.4.0->jsonschema>=2.6->nbformat>=4.2.0->ipywidgets->jupyter>=1.0.0->-r requirements.txt (line 12)) (3.7.0) Requirement already satisfied: jinja2 in c:\programdata\anaconda3\lib\site-packages (from notebook->jupyter>=1.0.0->-r requirements.txt (line 12)) (2.11.3) Requirement already satisfied: argon2-cffi in c:\programdata\anaconda3\lib\site-packages (from notebook->jupyter>=1.0.0->-r requirements.txt (line 12)) (21.3.0) Requirement already satisfied: prometheus-client in c:\programdata\anaconda3\lib\site-packages (from notebook->jupyter>=1.0.0->-r requirements.txt (line 12)) (0.13.1) Requirement already satisfied: Send2Trash>=1.8.0 in c:\programdata\anaconda3\lib\site-packages (from notebook->jupyter>=1.0.0->-r requirements.txt (line 12)) (1.8.0) Requirement already satisfied: terminado>=0.8.3 in c:\programdata\anaconda3\lib\site-packages (from notebook->jupyter>=1.0.0->-r requirements.txt (line 12)) (0.13.1) Requirement already satisfied: pywinpty>=1.1.0 in c:\programdata\anaconda3\lib\site-packages (from terminado>=0.8.3->notebook->jupyter>=1.0.0->-r requirements.txt (line 12)) (2.0.2) Requirement already satisfied: argon2-cffi-bindings in c:\programdata\anaconda3\lib\site-packages (from argon2-cffi->notebook->jupyter>=1.0.0->-r requirements.txt (line 12)) (21.2.0) Requirement already satisfied: cffi>=1.0.1 in c:\programdata\anaconda3\lib\site-packages (from argon2-cffi-bindings->argon2-cffi->notebook->jupyter>=1.0.0->-r requirements.txt (line 12)) (1.15.0) Requirement already satisfied: pycparser in c:\programdata\anaconda3\lib\site-packages (from cffi>=1.0.1->argon2-cffi-bindings->argon2-cffi->notebook->jupyter>=1.0.0->-r requirements.txt (line 12)) (2.21) Requirement already satisfied: MarkupSafe>=0.23 in c:\programdata\anaconda3\lib\site-packages (from jinja2->notebook->jupyter>=1.0.0->-r requirements.txt (line 12)) (2.0.1) Requirement already satisfied: jupyterlab-pygments in c:\programdata\anaconda3\lib\site-packages (from nbconvert->jupyter>=1.0.0->-r requirements.txt (line 12)) (0.1.2) Requirement already satisfied: defusedxml in c:\programdata\anaconda3\lib\site-packages (from nbconvert->jupyter>=1.0.0->-r requirements.txt (line 12)) (0.7.1) Requirement already satisfied: mistune<2,>=0.8.1 in c:\programdata\anaconda3\lib\site-packages (from nbconvert->jupyter>=1.0.0->-r requirements.txt (line 12)) (0.8.4) Requirement already satisfied: testpath in c:\programdata\anaconda3\lib\site-packages (from nbconvert->jupyter>=1.0.0->-r requirements.txt (line 12)) (0.5.0) Requirement already satisfied: bleach in c:\programdata\anaconda3\lib\site-packages (from nbconvert->jupyter>=1.0.0->-r requirements.txt (line 12)) (4.1.0) Requirement already satisfied: nbclient<0.6.0,>=0.5.0 in c:\programdata\anaconda3\lib\site-packages (from nbconvert->jupyter>=1.0.0->-r requirements.txt (line 12)) (0.5.13) Requirement already satisfied: entrypoints>=0.2.2 in c:\programdata\anaconda3\lib\site-packages (from nbconvert->jupyter>=1.0.0->-r requirements.txt (line 12)) (0.4) Requirement already satisfied: pandocfilters>=1.4.1 in c:\programdata\anaconda3\lib\site-packages (from nbconvert->jupyter>=1.0.0->-r requirements.txt (line 12)) (1.5.0) Requirement already satisfied: webencodings in c:\programdata\anaconda3\lib\site-packages (from bleach->nbconvert->jupyter>=1.0.0->-r requirements.txt (line 12)) (0.5.1) Requirement already satisfied: qtpy>=2.0.1 in c:\programdata\anaconda3\lib\site-packages (from qtconsole->jupyter>=1.0.0->-r requirements.txt (line 12)) (2.0.1) Requirement already satisfied: executing in c:\programdata\anaconda3\lib\site-packages (from stack-data->ipython>=7.23.1->ipykernel->jupyter>=1.0.0->-r requirements.txt (line 12)) (0.8.3) Requirement already satisfied: pure-eval in c:\programdata\anaconda3\lib\site-packages (from stack-data->ipython>=7.23.1->ipykernel->jupyter>=1.0.0->-r requirements.txt (line 12)) (0.2.2) Requirement already satisfied: asttokens in c:\programdata\anaconda3\lib\site-packages (from stack-data->ipython>=7.23.1->ipykernel->jupyter>=1.0.0->-r requirements.txt (line 12)) (2.0.5)
WARNING: Ignoring invalid distribution -finance (c:\programdata\anaconda3\lib\site-packages) WARNING: Ignoring invalid distribution - (c:\programdata\anaconda3\lib\site-packages) WARNING: Ignoring invalid distribution -finance (c:\programdata\anaconda3\lib\site-packages) WARNING: Ignoring invalid distribution - (c:\programdata\anaconda3\lib\site-packages) WARNING: Ignoring invalid distribution -finance (c:\programdata\anaconda3\lib\site-packages) WARNING: Ignoring invalid distribution - (c:\programdata\anaconda3\lib\site-packages) WARNING: Ignoring invalid distribution -finance (c:\programdata\anaconda3\lib\site-packages) WARNING: Ignoring invalid distribution - (c:\programdata\anaconda3\lib\site-packages) WARNING: Ignoring invalid distribution -finance (c:\programdata\anaconda3\lib\site-packages) WARNING: Ignoring invalid distribution - (c:\programdata\anaconda3\lib\site-packages) WARNING: Ignoring invalid distribution -finance (c:\programdata\anaconda3\lib\site-packages) WARNING: Ignoring invalid distribution - (c:\programdata\anaconda3\lib\site-packages)
If you prefer, manual installation can be done with the individual installation of the following libraries:
This document was prepared by Esteban Márquez Delgado as a delivery for Microstructure and Trading Systems - MAF1731B class during the Autumn 2022 course at ITESO for the Bachelor of Financial Engineering.
In the present work conceptual definitions of concern will be covered and evidence will be provided to answer the following question:
Data will be downloaded with YahooFinancials library according to provided csvs of NAFTRAC ETF holdings during periods of 2020/01/31 to 2022/07/29.
2. Concepts:
As of May 14, 2009 the name of the ETF covered in this paper changed from NAFTRAC to iShares NAFTRAC.
The benchmark is comprised of the largest stock issuers in the Mexican market with the purpose of being a reliable indicator of the market and the ETF iShares NAFTRAC from BlackRock serves as a financial instrument to invest in the index S&P/BMV IPC.
Passive investment : Invest in NAFTRAC (ETF) with cash restrictions limited to ETF tickers present in period of portfolio conformation for the selected fund (except: KOFL.MX, KOFUBL.MX, USD.MXN, BSMXB.MX, NMKA.MX).
There are several known advantages from investing in an ETF, including the following:
Reduced expenses.
Active investing : Actively rebalance an EMV portfolio and a constantly restructured portfolio, limited to ETF tickers present in all periods for the selected fund according to data in monthly csvs (NAFTRAC_20200131.csv to NAFTRAC_20220729.csv (31) ).
The advantages from actively managing a portfolio, include the following:
The main objective is to evaluate the following metrics:
## Libraries
# Analysis and data management
import pandas as pd
import pandas_datareader as pdr
import numpy as np
import datetime
from tkinter.ttk import Style
from tkinter import Y
import plotly.graph_objects as go #plotly
import plotly.express as px
from yahoofinancials import YahooFinancials # Yfinance
from scipy.optimize import minimize # Optimización
from collections import Counter #Counter
import re
import io
import glob
import os
import matplotlib.pyplot as plt # Visualization
import functions as fn
import visualizations as vs
import data as dt
import pandas as pd
from os import path
import fire
%matplotlib inline
Weights in Passive Portfolio consolidated in 2020-01-31 from NAFTRAC_20200131.csv
Note: KOFUBL.MX, BSMXB.MX, NMKA.MX and MXN positions are dropped from the dataframe and considered as cash.
help(dt.read_csv)
Help on function read_csv in module data:
read_csv(data)
Function that reads csv files and returns a dataframe of its content.
Parameters
----------
data: csv data.
Returns
-------
data: pd.DataFrame(data)
t=dt.read_csv('NAFTRAC_20200131.csv')[['Ticker','Peso (%)']].dropna().drop(10).drop(34).drop(32) #Read tickers and weights of first csv (port. consolidation).
W=(t['Peso (%)']/100).values #1-W.sum() Cash
t
| Ticker | Peso (%) | |
|---|---|---|
| 0 | AMXL | 13.70 |
| 1 | FEMSAUBD | 11.85 |
| 2 | GFNORTEO | 10.64 |
| 3 | WALMEX* | 10.39 |
| 4 | GMEXICOB | 6.03 |
| 5 | CEMEXCPO | 4.30 |
| 6 | TLEVISACPO | 3.96 |
| 7 | GAPB | 3.29 |
| 8 | ELEKTRA* | 3.02 |
| 9 | ASURB | 2.75 |
| 11 | KIMBERA | 2.06 |
| 12 | BIMBOA | 1.87 |
| 13 | OMAB | 1.85 |
| 14 | AC* | 1.77 |
| 15 | GFINBURO | 1.76 |
| 16 | IENOVA* | 1.73 |
| 17 | PINFRA* | 1.68 |
| 18 | GRUMAB | 1.68 |
| 19 | ORBIA* | 1.67 |
| 20 | ALFAA | 1.51 |
| 21 | GCARSOA1 | 1.16 |
| 22 | PE&OLES* | 0.91 |
| 23 | ALSEA* | 0.86 |
| 24 | BBAJIOO | 0.83 |
| 25 | GENTERA* | 0.81 |
| 26 | MEGACPO | 0.79 |
| 27 | LIVEPOLC.1 | 0.74 |
| 28 | BOLSAA | 0.72 |
| 29 | CUERVO* | 0.67 |
| 30 | LABB | 0.62 |
| 31 | GCC* | 0.59 |
| 33 | RA | 0.44 |
| 35 | ALPEKA | 0.25 |
In order, to retrieve specific help from the scripts in the project execute the help function on the script or in specific modules from the following:
help(vs.hist_csv)
Help on function hist_csv in module visualizations:
hist_csv(df, title, tickers, weights)
Function that returns histogram of tickers and weights of portfolio in a df.
Parameters
----------
df: Tickers and Weights of stocks in a dataframe.
title: Title of the histogram.
tickers: Column with tickers as str.
weights: Column with tickers as str.
Returns
-------
histogram of Tickers and Weights of the portfolio in a df.
vs.hist_csv(t, "Weights of Passive Portfolio (consolidation)",'Ticker','Peso (%)')
start = datetime.datetime(2020,1,31) #Portfolio conformation.
end = datetime.datetime(2022,7,29) #End of investment.
print('Download data and show summary of Passive Investment Portfolio from period', start.strftime("%Y-%m-%d"), 'to', end.strftime("%Y-%m-%d"))
Download data and show summary of Passive Investment Portfolio from period 2020-01-31 to 2022-07-29
capital = 1000000
com = -.00125
tickers=[stocks.replace('*','') for stocks in t['Ticker']+'.MX'] #Replace values to get readable tickers.
tickers[26]='LIVEPOLC-1.MX' #Replace a single value.
tickers
['AMXL.MX', 'FEMSAUBD.MX', 'GFNORTEO.MX', 'WALMEX.MX', 'GMEXICOB.MX', 'CEMEXCPO.MX', 'TLEVISACPO.MX', 'GAPB.MX', 'ELEKTRA.MX', 'ASURB.MX', 'KIMBERA.MX', 'BIMBOA.MX', 'OMAB.MX', 'AC.MX', 'GFINBURO.MX', 'IENOVA.MX', 'PINFRA.MX', 'GRUMAB.MX', 'ORBIA.MX', 'ALFAA.MX', 'GCARSOA1.MX', 'PE&OLES.MX', 'ALSEA.MX', 'BBAJIOO.MX', 'GENTERA.MX', 'MEGACPO.MX', 'LIVEPOLC-1.MX', 'BOLSAA.MX', 'CUERVO.MX', 'LABB.MX', 'GCC.MX', 'RA.MX', 'ALPEKA.MX']
help(dt.yf_adjclose)
Help on function yf_adjclose in module data:
yf_adjclose(tickers, start, end)
Function that downloads and returns yahoo finance ticker(s) adj. closes.
Parameters
----------
tickers: ticker(s) to download as a list.
start: datetime.datetime(y,m,d)
end: datetime.datetime(y,m,d)
Returns
-------
data: pd.DataFrame(data)
df=dt.yf_adjclose(tickers, start, end)
s0=df.head(1)
df.head()
| Symbols | AMXL.MX | FEMSAUBD.MX | GFNORTEO.MX | WALMEX.MX | GMEXICOB.MX | CEMEXCPO.MX | TLEVISACPO.MX | GAPB.MX | ELEKTRA.MX | ASURB.MX | KIMBERA.MX | BIMBOA.MX | OMAB.MX | AC.MX | GFINBURO.MX | IENOVA.MX | PINFRA.MX | GRUMAB.MX | ORBIA.MX | ALFAA.MX | GCARSOA1.MX | PE&OLES.MX | ALSEA.MX | BBAJIOO.MX | GENTERA.MX | MEGACPO.MX | LIVEPOLC-1.MX | BOLSAA.MX | CUERVO.MX | LABB.MX | GCC.MX | RA.MX | ALPEKA.MX |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Date | |||||||||||||||||||||||||||||||||
| 2020-01-31 | 14.346073 | 160.300339 | 105.844643 | 53.542744 | 42.370079 | 7.595 | 41.303806 | 216.240250 | 1366.929688 | 339.708923 | 34.365952 | 32.136036 | 122.502434 | 94.615448 | 21.424999 | 88.714996 | 188.090439 | 186.317108 | 40.384415 | 14.103790 | 66.101830 | 197.247894 | 45.825001 | 25.000610 | 20.633625 | 63.203465 | 92.458412 | 37.607738 | 33.807873 | 20.180393 | 95.766121 | 93.203430 | 17.603239 |
| 2020-02-04 | 14.615718 | 164.075867 | 106.049728 | 54.905067 | 45.631260 | 7.945 | 41.653214 | 220.965332 | 1364.359619 | 342.187866 | 34.286758 | 32.592335 | 123.128777 | 96.169991 | 22.600000 | 90.334999 | 188.348450 | 189.490524 | 42.516857 | 14.093850 | 67.263809 | 199.836685 | 45.849998 | 25.088739 | 20.736549 | 63.529854 | 91.039772 | 37.529819 | 34.795952 | 20.270689 | 96.513840 | 95.576775 | 17.429491 |
| 2020-02-05 | 14.524314 | 165.276321 | 105.789963 | 54.415405 | 44.998440 | 7.750 | 40.304802 | 222.125824 | 1360.484375 | 348.642487 | 34.207573 | 32.302391 | 122.753815 | 94.924583 | 22.240000 | 89.300003 | 186.841797 | 188.706436 | 42.621429 | 13.954700 | 64.905807 | 196.098434 | 46.240002 | 24.996605 | 21.094330 | 65.170746 | 89.495926 | 37.088291 | 34.708775 | 19.963692 | 95.384933 | 94.390106 | 17.295456 |
| 2020-02-06 | 14.332363 | 165.596451 | 105.871994 | 53.533047 | 44.213726 | 7.750 | 39.733936 | 221.940887 | 1348.394287 | 345.808105 | 34.269169 | 31.494360 | 123.580414 | 95.057083 | 21.400000 | 89.089996 | 188.058167 | 188.363144 | 42.257687 | 13.577009 | 63.982059 | 192.969894 | 46.099998 | 24.940521 | 20.829670 | 63.248177 | 86.992424 | 37.460564 | 33.556007 | 19.774078 | 91.485085 | 92.448273 | 17.166386 |
| 2020-02-07 | 14.295801 | 165.935410 | 103.894180 | 54.299053 | 43.741215 | 7.790 | 39.399296 | 223.771759 | 1375.075562 | 343.095245 | 33.952423 | 31.532379 | 122.762329 | 95.048256 | 22.040001 | 89.260002 | 186.758850 | 189.291031 | 41.930321 | 13.278831 | 64.137634 | 193.109833 | 45.200001 | 24.628065 | 20.623825 | 64.339119 | 87.159332 | 37.235466 | 32.761665 | 18.925327 | 94.319565 | 94.062141 | 16.967815 |
St=df.tail(1)
df.tail()
| Symbols | AMXL.MX | FEMSAUBD.MX | GFNORTEO.MX | WALMEX.MX | GMEXICOB.MX | CEMEXCPO.MX | TLEVISACPO.MX | GAPB.MX | ELEKTRA.MX | ASURB.MX | KIMBERA.MX | BIMBOA.MX | OMAB.MX | AC.MX | GFINBURO.MX | IENOVA.MX | PINFRA.MX | GRUMAB.MX | ORBIA.MX | ALFAA.MX | GCARSOA1.MX | PE&OLES.MX | ALSEA.MX | BBAJIOO.MX | GENTERA.MX | MEGACPO.MX | LIVEPOLC-1.MX | BOLSAA.MX | CUERVO.MX | LABB.MX | GCC.MX | RA.MX | ALPEKA.MX |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Date | |||||||||||||||||||||||||||||||||
| 2022-07-25 | 18.560059 | 121.089996 | 116.169998 | 71.860001 | 77.099358 | 8.31 | 32.240002 | 281.720001 | 1158.920044 | 382.739990 | 28.870001 | 74.239998 | 124.489998 | 139.020004 | 35.070000 | 73.699997 | 140.424179 | 251.630005 | 43.820000 | 14.10 | 76.989998 | 189.699997 | 38.910000 | 41.854561 | 16.309999 | 48.049999 | 89.320000 | 35.490002 | 45.610672 | 19.370001 | 118.410004 | 106.199997 | 26.900000 |
| 2022-07-26 | 18.394083 | 122.389999 | 114.300003 | 70.760002 | 74.858444 | 8.00 | 30.760000 | 270.549988 | 1172.030029 | 379.760010 | 28.870001 | 74.070000 | 120.959999 | 143.910004 | 34.950001 | 73.699997 | 139.952774 | 247.820007 | 43.470001 | 13.59 | 76.980003 | 187.960007 | 38.290001 | 42.102928 | 16.530001 | 47.689999 | 89.160004 | 36.000000 | 45.987213 | 18.709999 | 118.940002 | 105.669998 | 25.959999 |
| 2022-07-27 | 18.325741 | 124.250000 | 113.010002 | 71.459999 | 74.354973 | 8.03 | 31.190001 | 272.540009 | 1175.290039 | 380.459991 | 28.900000 | 73.070000 | 120.919998 | 140.130005 | 35.150002 | 73.699997 | 141.268814 | 248.479996 | 42.299999 | 14.03 | 77.959999 | 193.059998 | 38.580002 | 43.225185 | 17.150000 | 48.200001 | 89.589996 | 37.380001 | 46.700653 | 19.400000 | 120.930000 | 109.220001 | 27.219999 |
| 2022-07-28 | 18.892012 | 126.820000 | 117.650002 | 73.599998 | 77.632439 | 8.13 | 32.270000 | 278.489990 | 1184.459961 | 384.769989 | 29.299999 | 75.080002 | 124.400002 | 141.410004 | 37.430000 | 73.699997 | 142.604507 | 253.419998 | 43.939999 | 14.23 | 79.949997 | 211.360001 | 39.189999 | 43.777111 | 17.030001 | 47.779999 | 91.269997 | 37.590000 | 46.918648 | 19.320000 | 123.040001 | 111.230003 | 26.650000 |
| 2022-07-29 | 18.940828 | 127.029999 | 115.989998 | 73.839996 | 79.567329 | 8.23 | 32.139999 | 276.399994 | 1197.390015 | 384.000000 | 30.020000 | 72.040001 | 124.169998 | 141.210007 | 37.540001 | 73.699997 | 144.411606 | 253.490005 | 44.959999 | 14.01 | 79.510002 | 205.080002 | 39.660000 | 44.099068 | 16.570000 | 47.410000 | 91.480003 | 37.939999 | 45.719669 | 18.950001 | 125.989998 | 111.370003 | 27.110001 |
help(vs.stocks_summary)
Help on function stocks_summary in module visualizations:
stocks_summary(s0, St, W, capital, returns, mean_ret)
Function that returns a stock summary of the behavior of a portfolio in a given date
with known initial global investment, returns of assets, weights and S0 and St.
Parameters
----------
s0: Initial price in a dataframe of 1*n.
St: Last price in a dataframe of 1*n.
W: Weights of holdings as an array.
capital: Scalar of capital amount.
returns: Dataframe of holdings returns.
mean_ret: Mean returns of holdings.
Returns
-------
A dataframe with the behavior of Holdings (S_0, S_t, Owned Titles, Initial_investment, Return and Volatility in a given period).
returns, mean_ret, cov= fn.s_metrics(df)[0], fn.s_metrics(df)[1], fn.s_metrics(df)[2]
stocks_summary=vs.stocks_summary(s0,St, W, capital, returns, mean_ret)
stocks_summary
| S_0 | S_t | Rounded_Titles | Initial_Investment | Return | Volatility | |
|---|---|---|---|---|---|---|
| Symbols | ||||||
| AMXL.MX | 14.346073 | 18.940828 | 9550.0 | 137004.998589 | 0.148598 | 0.273509 |
| FEMSAUBD.MX | 160.300339 | 127.029999 | 739.0 | 118461.950333 | -0.052876 | 0.284635 |
| GFNORTEO.MX | 105.844643 | 115.989998 | 1005.0 | 106373.865852 | 0.126355 | 0.423030 |
| WALMEX.MX | 53.542744 | 73.839996 | 1941.0 | 103926.465488 | 0.167182 | 0.278108 |
| GMEXICOB.MX | 42.370079 | 79.567329 | 1423.0 | 60292.622475 | 0.332085 | 0.400770 |
| CEMEXCPO.MX | 7.595000 | 8.230000 | 5662.0 | 43002.888812 | 0.141860 | 0.470635 |
| TLEVISACPO.MX | 41.303806 | 32.139999 | 959.0 | 39610.350246 | 0.012703 | 0.479625 |
| GAPB.MX | 216.240250 | 276.399994 | 152.0 | 32868.517944 | 0.188951 | 0.423914 |
| ELEKTRA.MX | 1366.929688 | 1197.390015 | 22.0 | 30072.453125 | -0.040061 | 0.161066 |
| ASURB.MX | 339.708923 | 384.000000 | 81.0 | 27516.422791 | 0.114147 | 0.361635 |
| KIMBERA.MX | 34.365952 | 30.020000 | 599.0 | 20585.204971 | -0.006264 | 0.310031 |
| BIMBOA.MX | 32.136036 | 72.040001 | 582.0 | 18703.172905 | 0.398483 | 0.389774 |
| OMAB.MX | 122.502434 | 124.169998 | 151.0 | 18497.867500 | 0.092444 | 0.417460 |
| AC.MX | 94.615448 | 141.210007 | 187.0 | 17693.088776 | 0.188716 | 0.239398 |
| GFINBURO.MX | 21.424999 | 37.540001 | 821.0 | 17589.924374 | 0.303244 | 0.396569 |
| IENOVA.MX | 88.714996 | 73.699997 | 195.0 | 17299.424286 | -0.034846 | 0.279192 |
| PINFRA.MX | 188.090439 | 144.411606 | 89.0 | 16740.049057 | -0.063772 | 0.289097 |
| GRUMAB.MX | 186.317108 | 253.490005 | 90.0 | 16768.539734 | 0.165898 | 0.292974 |
| ORBIA.MX | 40.384415 | 44.959999 | 414.0 | 16719.147675 | 0.112671 | 0.372697 |
| ALFAA.MX | 14.103790 | 14.010000 | 1071.0 | 15105.159393 | 0.108199 | 0.471404 |
| GCARSOA1.MX | 66.101830 | 79.510002 | 175.0 | 11567.820168 | 0.165908 | 0.429436 |
| PE&OLES.MX | 197.247894 | 205.080002 | 46.0 | 9073.403137 | 0.125442 | 0.471795 |
| ALSEA.MX | 45.825001 | 39.660000 | 188.0 | 8615.100143 | 0.066328 | 0.485726 |
| BBAJIOO.MX | 25.000610 | 44.099068 | 332.0 | 8300.202637 | 0.300099 | 0.381890 |
| GENTERA.MX | 20.633625 | 16.570000 | 393.0 | 8109.014637 | 0.047251 | 0.522969 |
| MEGACPO.MX | 63.203465 | 47.410000 | 125.0 | 7900.433064 | -0.073475 | 0.289133 |
| LIVEPOLC-1.MX | 92.458412 | 91.480003 | 80.0 | 7396.672974 | 0.061739 | 0.363073 |
| BOLSAA.MX | 37.607738 | 37.939999 | 191.0 | 7183.078053 | 0.067481 | 0.360801 |
| CUERVO.MX | 33.807873 | 45.719669 | 198.0 | 6693.958809 | 0.168834 | 0.311243 |
| LABB.MX | 20.180393 | 18.950001 | 307.0 | 6195.380718 | 0.039878 | 0.360957 |
| GCC.MX | 95.766121 | 125.989998 | 62.0 | 5937.499496 | 0.157187 | 0.308055 |
| RA.MX | 93.203430 | 111.370003 | 47.0 | 4380.561218 | 0.163949 | 0.428491 |
| ALPEKA.MX | 17.603239 | 27.110001 | 142.0 | 2499.659946 | 0.234068 | 0.350800 |
pd.set_option('display.float_format', lambda x: '%.4f' % x)
I_inv = stocks_summary.Initial_Investment.sum()
cash = capital-I_inv
passive_summary = pd.DataFrame({'Portfolio_IV':I_inv+cash, "Cash": cash, 'Commision':I_inv*com}, index=['Passive_Summary'])
passive_summary
| Portfolio_IV | Cash | Commision | |
|---|---|---|---|
| Passive_Summary | 1000000.0000 | 31315.1007 | -1210.8561 |
print("The Passive Investment portfolio started with a capital of", I_inv.round(2), '+ cash')
The Passive Investment portfolio started with a capital of 968684.9 + cash
The returns of the assets composing the ETF and the portfolio are calculated on a daily basis in order to get the accumulated returns for each day on the dataframe shown below and to plot the behavior of the portfolio more precisely.
port_pas=vs.port_pasivo(returns, W, capital, I_inv, com, cash)
port_pas.head()
| Symbols | AMXL.MX | FEMSAUBD.MX | GFNORTEO.MX | WALMEX.MX | GMEXICOB.MX | CEMEXCPO.MX | TLEVISACPO.MX | GAPB.MX | ELEKTRA.MX | ASURB.MX | KIMBERA.MX | BIMBOA.MX | OMAB.MX | AC.MX | GFINBURO.MX | IENOVA.MX | PINFRA.MX | GRUMAB.MX | ORBIA.MX | ALFAA.MX | GCARSOA1.MX | PE&OLES.MX | ALSEA.MX | BBAJIOO.MX | GENTERA.MX | MEGACPO.MX | LIVEPOLC-1.MX | BOLSAA.MX | CUERVO.MX | LABB.MX | GCC.MX | RA.MX | ALPEKA.MX | Capital | Portfolio Returns | Accumulated Returns |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| timestamp | ||||||||||||||||||||||||||||||||||||
| 2020-01-31 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 998789.1439 | -0.0012 | 0.9988 |
| 2020-02-04 | 2575.0133 | 2791.0113 | 206.1618 | 2643.5970 | 4641.2282 | 1981.5690 | 334.9939 | 718.9004 | -56.7813 | 200.6745 | -47.4708 | 265.5209 | 94.5887 | 290.8130 | 965.2285 | 315.9110 | 23.0452 | 286.1433 | 881.8201 | -10.6423 | 203.9121 | 119.4335 | 4.6913 | 29.2581 | 40.4043 | 40.7964 | -113.5423 | -14.9176 | 195.8162 | 27.7415 | 46.0658 | 112.0422 | -24.6756 | 1018557.4959 | 0.0198 | 1.0186 |
| 2020-02-05 | -856.7723 | 867.0007 | -260.6236 | -926.6157 | -836.2481 | -1055.3816 | -1281.9443 | 172.7881 | -85.7782 | 518.7269 | -47.5758 | -166.3565 | -56.3377 | -229.2161 | -280.3545 | -198.2115 | -134.3880 | -69.5163 | 41.0745 | -149.0845 | -406.6499 | -170.2294 | 73.1522 | -30.4805 | 139.7543 | 204.0465 | -125.4887 | -84.7061 | -16.7861 | -93.8983 | -69.0113 | -54.6298 | -19.2253 | 1012868.5290 | -0.0056 | 1.0129 |
| 2020-02-06 | -1810.5681 | 229.5267 | 82.5043 | -1684.7629 | -1051.5529 | 0.0000 | -560.8830 | -27.3917 | -268.3755 | -223.5685 | 37.0934 | -467.7728 | 124.5752 | 24.7064 | -664.7483 | -40.6844 | 109.3707 | -30.5623 | -142.5223 | -408.6884 | -165.0927 | -145.1807 | -26.0387 | -18.6223 | -101.6266 | -233.0539 | -207.0029 | 72.2698 | -222.5241 | -58.8870 | -241.2237 | -90.5187 | -18.6567 | 1004638.0663 | -0.0081 | 1.0046 |
| 2020-02-07 | -349.4880 | 242.5572 | -1987.6775 | 1486.7092 | -644.4250 | 221.9353 | -333.5125 | 271.4041 | 597.5808 | -215.7371 | -190.4033 | 22.5742 | -122.4674 | -1.6437 | 526.3562 | 33.0127 | -116.0732 | 82.7577 | -129.3732 | -331.6266 | 28.2058 | 6.5992 | -167.8955 | -103.9828 | -80.0466 | 136.2639 | 14.1980 | -43.2642 | -158.6032 | -266.1189 | 182.7996 | 76.8108 | -28.9185 | 1003296.5736 | -0.0013 | 1.0033 |
port_pas.tail()
| Symbols | AMXL.MX | FEMSAUBD.MX | GFNORTEO.MX | WALMEX.MX | GMEXICOB.MX | CEMEXCPO.MX | TLEVISACPO.MX | GAPB.MX | ELEKTRA.MX | ASURB.MX | KIMBERA.MX | BIMBOA.MX | OMAB.MX | AC.MX | GFINBURO.MX | IENOVA.MX | PINFRA.MX | GRUMAB.MX | ORBIA.MX | ALFAA.MX | GCARSOA1.MX | PE&OLES.MX | ALSEA.MX | BBAJIOO.MX | GENTERA.MX | MEGACPO.MX | LIVEPOLC-1.MX | BOLSAA.MX | CUERVO.MX | LABB.MX | GCC.MX | RA.MX | ALPEKA.MX | Capital | Portfolio Returns | Accumulated Returns |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| timestamp | ||||||||||||||||||||||||||||||||||||
| 2022-07-25 | -1355.7434 | -497.0004 | 2445.4392 | -2013.3435 | -138.6580 | 470.8037 | -365.0882 | -353.5147 | 208.0710 | 87.9378 | -494.4551 | -50.2430 | 286.7284 | 121.7857 | 151.8547 | 0.0000 | -86.5020 | 143.4232 | -158.5450 | -273.3976 | -37.5453 | -185.1581 | 236.1766 | 95.9542 | -170.1683 | -19.6801 | -9.9287 | 36.7035 | 100.4631 | -82.1187 | -10.4451 | 102.1677 | -0.9290 | 1260881.9258 | -0.0014 | 1.2609 |
| 2022-07-26 | -1225.1391 | 1272.1973 | -1712.7269 | -1590.4514 | -1752.6356 | -1604.0935 | -1817.8677 | -1304.4634 | 341.6297 | -214.1126 | 0.0000 | -42.8201 | -524.5801 | 622.5938 | -60.2219 | 0.0000 | -56.3977 | -254.3733 | -133.3860 | -546.1704 | -1.5059 | -83.4682 | -137.0339 | 49.2527 | 109.2587 | -59.1884 | -13.2554 | 103.4654 | 55.3122 | -211.2551 | 26.4082 | -21.9585 | -87.3606 | 1250007.5778 | -0.0086 | 1.2500 |
| 2022-07-27 | -509.0160 | 1800.8830 | -1200.8407 | 1027.8361 | -405.5564 | 161.2486 | 553.5765 | 241.9948 | 84.0015 | 50.6886 | 21.4054 | -252.4639 | -6.1179 | -464.9154 | 100.7157 | 0.0000 | 157.9781 | 44.7414 | -449.4832 | 488.8884 | 147.6741 | 246.9138 | 65.1347 | 221.2372 | 303.8107 | 84.4835 | 35.6880 | 276.0002 | 103.9430 | 228.6480 | 98.7135 | 147.8188 | 121.3406 | 1253534.5484 | 0.0028 | 1.2535 |
| 2022-07-28 | 4233.3406 | 2451.0661 | 4368.6039 | 3111.4741 | 2657.9418 | 535.4940 | 1371.2086 | 718.2593 | 235.6283 | 311.5306 | 285.1208 | 514.3977 | 532.4186 | 161.6783 | 1141.6210 | 0.0000 | 158.8436 | 333.9989 | 647.4702 | 215.2528 | 296.1003 | 862.5817 | 135.9765 | 105.9795 | -56.6759 | -68.8385 | 138.7655 | 40.4493 | 31.2750 | -25.5670 | 102.9439 | 80.9743 | -52.3512 | 1279111.5111 | 0.0204 | 1.2791 |
| 2022-07-29 | 354.0060 | 196.2221 | -1501.2698 | 338.8013 | 1502.9015 | 528.9023 | -159.5303 | -246.9061 | 329.6757 | -55.0321 | 506.2125 | -757.1659 | -34.2047 | -25.0332 | 51.7235 | 0.0000 | 212.8913 | 4.6410 | 387.6652 | -233.4497 | -63.8391 | -270.3822 | 103.1388 | 61.0419 | -218.7908 | -61.1760 | 17.0270 | 67.0388 | -171.2146 | -118.7367 | 141.4579 | 5.5380 | 43.1521 | 1280046.8167 | 0.0007 | 1.2800 |
A summary of the capital behavior, its monthly and accumulated returns is shown on the next dataframe.
df_pasiva=vs.df_pasiva(port_pas)
df_pasiva['timestamp']=df_pasiva.index
df_pasiva[['timestamp', 'Capital', 'Portfolio Returns', 'Accumulated Returns']].reset_index(drop=True)
| Symbols | timestamp | Capital | Portfolio Returns | Accumulated Returns |
|---|---|---|---|---|
| 0 | 2020-01-31 | 998789.1439 | -0.0012 | 0.9988 |
| 1 | 2020-02-28 | 937043.2657 | -0.0058 | 0.9370 |
| 2 | 2020-03-31 | 767564.7940 | 0.0147 | 0.7676 |
| 3 | 2020-04-30 | 833851.1775 | -0.0109 | 0.8339 |
| 4 | 2020-05-29 | 839549.0464 | -0.0129 | 0.8395 |
| 5 | 2020-06-30 | 895077.4327 | -0.0010 | 0.8951 |
| 6 | 2020-07-31 | 879866.4674 | -0.0028 | 0.8799 |
| 7 | 2020-08-31 | 881342.5886 | -0.0273 | 0.8813 |
| 8 | 2020-09-30 | 900998.5648 | 0.0089 | 0.9010 |
| 9 | 2020-10-30 | 892971.2885 | 0.0046 | 0.8930 |
| 10 | 2020-11-30 | 1037201.5549 | 0.0020 | 1.0372 |
| 11 | 2020-12-31 | 1089432.9928 | -0.0116 | 1.0894 |
| 12 | 2021-01-29 | 1059641.4580 | -0.0266 | 1.0596 |
| 13 | 2021-02-26 | 1092550.5699 | 0.0066 | 1.0926 |
| 14 | 2021-03-31 | 1152784.9473 | -0.0135 | 1.1528 |
| 15 | 2021-04-30 | 1186455.5197 | -0.0123 | 1.1865 |
| 16 | 2021-05-31 | 1252749.9830 | 0.0131 | 1.2527 |
| 17 | 2021-06-30 | 1245206.2836 | -0.0010 | 1.2452 |
| 18 | 2021-07-30 | 1263823.1701 | -0.0090 | 1.2638 |
| 19 | 2021-08-31 | 1311200.5377 | 0.0098 | 1.3112 |
| 20 | 2021-09-30 | 1286457.8696 | 0.0050 | 1.2865 |
| 21 | 2021-10-29 | 1290072.3425 | 0.0008 | 1.2901 |
| 22 | 2021-11-30 | 1264996.0019 | -0.0018 | 1.2650 |
| 23 | 2021-12-31 | 1335490.4062 | 0.0016 | 1.3355 |
| 24 | 2022-01-31 | 1306098.0059 | 0.0094 | 1.3061 |
| 25 | 2022-02-28 | 1345925.0703 | 0.0119 | 1.3459 |
| 26 | 2022-03-31 | 1403510.5447 | 0.0079 | 1.4035 |
| 27 | 2022-04-29 | 1322158.2000 | -0.0154 | 1.3222 |
| 28 | 2022-05-31 | 1342524.9296 | -0.0049 | 1.3425 |
| 29 | 2022-06-30 | 1269600.5959 | -0.0076 | 1.2696 |
| 30 | 2022-07-29 | 1280046.8167 | 0.0007 | 1.2800 |
The following plot shows the behavior of the portfolio during the investment period.
help(vs.plot)
Help on function plot in module visualizations:
plot(metric, title, xlabel, ylabel)
Function that converts the capital in a portfolio, its returns and accumulated returns to a monthly basis.
Parameters
----------
port_pas: Dataframe that contains 'Capital', 'Portfolio Returns' and 'Accumulated Returns' columns in order.
Returns
-------
A monthly dataframe of the Capital the Monthly Return and Accumulated Return for the investment in a period.
vs.plot(port_pas.Capital, 'Passive Investment (Daily)', 'Date', 'Capital')
help(vs.plotly_graph)
Help on function plotly_graph in module visualizations:
plotly_graph(x, y, x_label, y_label, title)
Function that plots a line+marker graph with plotly.
Parameters
----------
x: index from Dataframe of selected metric to graph with plotly.
y: Values of the selected of selected metric to graph with plotly.
title: Title of the plot.
x_label: Variable name in the label x.
y_label: Variable name in the label y.
Returns
-------
Returns a didactic graph with plotly of the selected metric.
vs.plotly_graph(x=df_pasiva['timestamp'], y=df_pasiva['Capital'], title="Passive Investment Capital", x_label='Dates', y_label="Capital")
vs.plotly_graph(x=df_pasiva['timestamp'], y=df_pasiva['Portfolio Returns'], title="Passive Investment Returns", x_label='Dates', y_label="Capital")
Ticker selection from constant re appearance in CSVs.
pd.options.mode.chained_assignment = None
extension = 'csv'
all_filenames = [i for i in glob.glob('*.{}'.format(extension))] #read all csvs in one line
combined_csv = pd.concat([pd.read_csv(f) for f in all_filenames ]).dropna() #concatenate in a df
tick_rep = Counter(combined_csv['Ticker']) #count occurences
tick_sorted = sorted(tick_rep.items(), key=lambda kv: kv[1]) #sort first values of tuple by occurence
print("ticker_list", str(tick_sorted)) #print all strings of tuples despite number of occurrence
ticker_selection = [i for i in tick_sorted if i[1] >= 31] #List compression to filter tickers by max n° of occurence
#ticker_selection[24] = ('LIVEPOLC-1','31') #Rename LIVEPOLC.1 to downloadable data
ticker_selection #results
ticker_list [('USD', 2), ('ALPEKA', 3), ('NMKA', 3), ('SITES1A-1', 5), ('BSMXB', 8), ('VOLARA', 11), ('GENTERA*', 14), ('IENOVA*', 16), ('SITESB.1', 18), ('RA', 25), ('GCC*', 26), ('VESTA*', 28), ('Q*', 28), ('AMXL', 31), ('FEMSAUBD', 31), ('GFNORTEO', 31), ('WALMEX*', 31), ('GMEXICOB', 31), ('CEMEXCPO', 31), ('TLEVISACPO', 31), ('GAPB', 31), ('ELEKTRA*', 31), ('ASURB', 31), ('KOFUBL', 31), ('KIMBERA', 31), ('BIMBOA', 31), ('OMAB', 31), ('AC*', 31), ('GFINBURO', 31), ('PINFRA*', 31), ('GRUMAB', 31), ('ORBIA*', 31), ('ALFAA', 31), ('GCARSOA1', 31), ('PE&OLES*', 31), ('ALSEA*', 31), ('BBAJIOO', 31), ('MEGACPO', 31), ('LIVEPOLC.1', 31), ('BOLSAA', 31), ('CUERVO*', 31), ('LABB', 31), ('MXN', 31)]
[('AMXL', 31),
('FEMSAUBD', 31),
('GFNORTEO', 31),
('WALMEX*', 31),
('GMEXICOB', 31),
('CEMEXCPO', 31),
('TLEVISACPO', 31),
('GAPB', 31),
('ELEKTRA*', 31),
('ASURB', 31),
('KOFUBL', 31),
('KIMBERA', 31),
('BIMBOA', 31),
('OMAB', 31),
('AC*', 31),
('GFINBURO', 31),
('PINFRA*', 31),
('GRUMAB', 31),
('ORBIA*', 31),
('ALFAA', 31),
('GCARSOA1', 31),
('PE&OLES*', 31),
('ALSEA*', 31),
('BBAJIOO', 31),
('MEGACPO', 31),
('LIVEPOLC.1', 31),
('BOLSAA', 31),
('CUERVO*', 31),
('LABB', 31),
('MXN', 31)]
For not consolidating NAFTRAC in all periods IENOVA.MX, GENTERA.MX, GCC.MX, RA.MX AND ALPEKA.MX should be removed from the ticker selection as well as the tickers KOFL.MX, KOFUBL.MX, USD.MXN, BSMXB.MX, NMKA.MX (2. Concepts section).
t2= pd.read_csv('NAFTRAC_20200131.csv')[['Ticker','Peso (%)']].drop(10).drop(16).drop(25).drop(31).drop(32).drop(33).drop(34).drop(35).drop(36)
W2=t2['Peso (%)']/100 #1-W2.sum() Cash
t2.Ticker[27]='LIVEPOLC-1'
tickers_ap=[stocks.replace('*','') for stocks in t2.Ticker + '.MX']
tickers_ap
['AMXL.MX', 'FEMSAUBD.MX', 'GFNORTEO.MX', 'WALMEX.MX', 'GMEXICOB.MX', 'CEMEXCPO.MX', 'TLEVISACPO.MX', 'GAPB.MX', 'ELEKTRA.MX', 'ASURB.MX', 'KIMBERA.MX', 'BIMBOA.MX', 'OMAB.MX', 'AC.MX', 'GFINBURO.MX', 'PINFRA.MX', 'GRUMAB.MX', 'ORBIA.MX', 'ALFAA.MX', 'GCARSOA1.MX', 'PE&OLES.MX', 'ALSEA.MX', 'BBAJIOO.MX', 'MEGACPO.MX', 'LIVEPOLC-1.MX', 'BOLSAA.MX', 'CUERVO.MX', 'LABB.MX']
start = datetime.datetime(2020,1,31) #Portfolio conformation.
end = datetime.datetime(2021,1,31) #End of investment.
print('Download data and show summary of Active Investment Portfolio (EMV) from period', start.strftime("%Y-%m-%d"), 'to', end.strftime("%Y-%m-%d"))
Download data and show summary of Active Investment Portfolio (EMV) from period 2020-01-31 to 2021-01-31
df2=dt.yf_adjclose(tickers_ap, start, end)
s0=df2.head(1)
df2.head()
| Symbols | AMXL.MX | FEMSAUBD.MX | GFNORTEO.MX | WALMEX.MX | GMEXICOB.MX | CEMEXCPO.MX | TLEVISACPO.MX | GAPB.MX | ELEKTRA.MX | ASURB.MX | KIMBERA.MX | BIMBOA.MX | OMAB.MX | AC.MX | GFINBURO.MX | PINFRA.MX | GRUMAB.MX | ORBIA.MX | ALFAA.MX | GCARSOA1.MX | PE&OLES.MX | ALSEA.MX | BBAJIOO.MX | MEGACPO.MX | LIVEPOLC-1.MX | BOLSAA.MX | CUERVO.MX | LABB.MX |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Date | ||||||||||||||||||||||||||||
| 2020-01-31 | 14.3461 | 160.3003 | 105.8447 | 53.5427 | 42.3701 | 7.5950 | 41.3038 | 216.2402 | 1366.9298 | 339.7089 | 34.3659 | 32.1360 | 122.5024 | 94.6155 | 21.4250 | 188.0904 | 186.3171 | 40.3844 | 14.1038 | 66.1018 | 197.2479 | 45.8250 | 25.0006 | 63.2035 | 92.4584 | 37.6077 | 33.8079 | 20.1804 |
| 2020-02-04 | 14.6157 | 164.0759 | 106.0497 | 54.9051 | 45.6313 | 7.9450 | 41.6532 | 220.9653 | 1364.3595 | 342.1879 | 34.2868 | 32.5923 | 123.1288 | 96.1700 | 22.6000 | 188.3484 | 189.4905 | 42.5169 | 14.0939 | 67.2638 | 199.8367 | 45.8500 | 25.0887 | 63.5299 | 91.0398 | 37.5298 | 34.7960 | 20.2707 |
| 2020-02-05 | 14.5243 | 165.2763 | 105.7900 | 54.4154 | 44.9984 | 7.7500 | 40.3048 | 222.1258 | 1360.4844 | 348.6425 | 34.2076 | 32.3024 | 122.7538 | 94.9246 | 22.2400 | 186.8418 | 188.7065 | 42.6214 | 13.9547 | 64.9058 | 196.0984 | 46.2400 | 24.9966 | 65.1707 | 89.4959 | 37.0883 | 34.7088 | 19.9637 |
| 2020-02-06 | 14.3324 | 165.5965 | 105.8720 | 53.5331 | 44.2137 | 7.7500 | 39.7339 | 221.9409 | 1348.3944 | 345.8081 | 34.2692 | 31.4944 | 123.5804 | 95.0571 | 21.4000 | 188.0582 | 188.3631 | 42.2577 | 13.5770 | 63.9821 | 192.9699 | 46.1000 | 24.9405 | 63.2482 | 86.9924 | 37.4606 | 33.5560 | 19.7741 |
| 2020-02-07 | 14.2958 | 165.9354 | 103.8942 | 54.2990 | 43.7412 | 7.7900 | 39.3993 | 223.7717 | 1375.0756 | 343.0952 | 33.9524 | 31.5324 | 122.7623 | 95.0482 | 22.0400 | 186.7589 | 189.2910 | 41.9303 | 13.2788 | 64.1376 | 193.1098 | 45.2000 | 24.6281 | 64.3391 | 87.1593 | 37.2355 | 32.7617 | 18.9253 |
St=df2.tail(1)
df2.tail()
| Symbols | AMXL.MX | FEMSAUBD.MX | GFNORTEO.MX | WALMEX.MX | GMEXICOB.MX | CEMEXCPO.MX | TLEVISACPO.MX | GAPB.MX | ELEKTRA.MX | ASURB.MX | KIMBERA.MX | BIMBOA.MX | OMAB.MX | AC.MX | GFINBURO.MX | PINFRA.MX | GRUMAB.MX | ORBIA.MX | ALFAA.MX | GCARSOA1.MX | PE&OLES.MX | ALSEA.MX | BBAJIOO.MX | MEGACPO.MX | LIVEPOLC-1.MX | BOLSAA.MX | CUERVO.MX | LABB.MX |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Date | ||||||||||||||||||||||||||||
| 2021-01-25 | 13.9326 | 144.7866 | 96.4022 | 60.6645 | 82.4846 | 12.4300 | 34.2123 | 193.2389 | 1388.7820 | 301.1777 | 33.6193 | 40.7484 | 103.1456 | 89.3091 | 19.0700 | 155.4610 | 222.3233 | 43.7959 | 13.4238 | 59.5189 | 316.2923 | 22.9800 | 20.0293 | 69.2293 | 63.1121 | 42.3578 | 46.6492 | 19.8102 |
| 2021-01-26 | 13.7800 | 143.6113 | 96.0103 | 60.7338 | 81.2241 | 12.3800 | 34.9800 | 197.6681 | 1382.7607 | 307.9223 | 34.5690 | 40.4880 | 103.4438 | 89.2812 | 19.3400 | 154.6244 | 221.7306 | 44.6861 | 13.7425 | 58.2548 | 321.4899 | 22.7800 | 19.8931 | 69.4681 | 63.2373 | 42.2585 | 46.1875 | 19.7470 |
| 2021-01-27 | 13.5702 | 143.0429 | 94.5885 | 59.4860 | 81.1258 | 11.8400 | 32.5194 | 191.8519 | 1384.5959 | 307.2955 | 34.1080 | 39.0413 | 101.1771 | 87.9604 | 19.0100 | 149.6233 | 219.6945 | 44.1788 | 13.7723 | 56.0183 | 299.4502 | 22.5700 | 19.6207 | 69.4865 | 64.1428 | 42.1049 | 44.2721 | 20.0901 |
| 2021-01-28 | 13.3986 | 141.3377 | 97.0220 | 59.4266 | 81.2420 | 12.1700 | 32.5785 | 192.0923 | 1378.2570 | 303.9747 | 33.8037 | 38.7037 | 102.4639 | 88.3139 | 18.9200 | 147.0182 | 218.9585 | 44.1213 | 13.6230 | 53.9180 | 300.7696 | 22.9300 | 19.1641 | 70.7267 | 63.5552 | 41.6894 | 42.9656 | 20.0540 |
| 2021-01-29 | 13.0362 | 134.5844 | 92.5742 | 57.7828 | 78.5244 | 11.7600 | 30.5017 | 191.0382 | 1374.9238 | 301.7109 | 33.0199 | 37.1510 | 103.1030 | 86.5653 | 18.2800 | 146.4762 | 215.1349 | 42.2929 | 12.8462 | 50.1646 | 306.6068 | 23.1100 | 19.8370 | 68.0902 | 63.1025 | 41.5539 | 42.9558 | 18.9524 |
log_ret, mean_lr, cov= fn.log_metrics(df2)[1], fn.log_metrics(df2)[2], fn.log_metrics(df2)[4]
stocks_summary2=vs.stocks_summary(s0,St, W2.values.flatten(), capital, log_ret, mean_lr)
stocks_summary2
| S_0 | S_t | Rounded_Titles | Initial_Investment | Return | Volatility | |
|---|---|---|---|---|---|---|
| Symbols | ||||||
| AMXL.MX | 14.3461 | 13.0362 | 9550.0000 | 137004.9895 | -0.0961 | 0.3322 |
| FEMSAUBD.MX | 160.3003 | 134.5844 | 739.0000 | 118461.9503 | -0.1756 | 0.3518 |
| GFNORTEO.MX | 105.8447 | 92.5742 | 1005.0000 | 106373.8735 | -0.1345 | 0.5051 |
| WALMEX.MX | 53.5427 | 57.7828 | 1941.0000 | 103926.4655 | 0.0765 | 0.2923 |
| GMEXICOB.MX | 42.3701 | 78.5244 | 1423.0000 | 60292.6279 | 0.6194 | 0.4185 |
| CEMEXCPO.MX | 7.5950 | 11.7600 | 5662.0000 | 43002.8888 | 0.4390 | 0.5539 |
| TLEVISACPO.MX | 41.3038 | 30.5017 | 959.0000 | 39610.3502 | -0.3044 | 0.5762 |
| GAPB.MX | 216.2402 | 191.0382 | 152.0000 | 32868.5179 | -0.1244 | 0.5715 |
| ELEKTRA.MX | 1366.9298 | 1374.9238 | 22.0000 | 30072.4558 | 0.0059 | 0.1346 |
| ASURB.MX | 339.7089 | 301.7109 | 81.0000 | 27516.4228 | -0.1191 | 0.4683 |
| KIMBERA.MX | 34.3659 | 33.0199 | 599.0000 | 20585.2004 | -0.0401 | 0.3544 |
| BIMBOA.MX | 32.1360 | 37.1510 | 582.0000 | 18703.1729 | 0.1456 | 0.4416 |
| OMAB.MX | 122.5024 | 103.1030 | 151.0000 | 18497.8675 | -0.1731 | 0.5701 |
| AC.MX | 94.6155 | 86.5653 | 187.0000 | 17693.0902 | -0.0893 | 0.2685 |
| GFINBURO.MX | 21.4250 | 18.2800 | 821.0000 | 17589.9244 | -0.1594 | 0.5122 |
| PINFRA.MX | 188.0904 | 146.4762 | 89.0000 | 16740.0477 | -0.2511 | 0.3759 |
| GRUMAB.MX | 186.3171 | 215.1349 | 90.0000 | 16768.5397 | 0.1444 | 0.3517 |
| ORBIA.MX | 40.3844 | 42.2929 | 414.0000 | 16719.1477 | 0.0464 | 0.4947 |
| ALFAA.MX | 14.1038 | 12.8462 | 1071.0000 | 15105.1584 | -0.0938 | 0.6596 |
| GCARSOA1.MX | 66.1018 | 50.1646 | 175.0000 | 11567.8202 | -0.2770 | 0.5190 |
| PE&OLES.MX | 197.2479 | 306.6068 | 46.0000 | 9073.4031 | 0.4429 | 0.5891 |
| ALSEA.MX | 45.8250 | 23.1100 | 188.0000 | 8615.1001 | -0.6873 | 0.6886 |
| BBAJIOO.MX | 25.0006 | 19.8370 | 332.0000 | 8300.2026 | -0.2323 | 0.4701 |
| MEGACPO.MX | 63.2035 | 68.0902 | 125.0000 | 7900.4326 | 0.0748 | 0.3491 |
| LIVEPOLC-1.MX | 92.4584 | 63.1025 | 80.0000 | 7396.6748 | -0.3835 | 0.4678 |
| BOLSAA.MX | 37.6077 | 41.5539 | 191.0000 | 7183.0781 | 0.1002 | 0.4644 |
| CUERVO.MX | 33.8079 | 42.9558 | 198.0000 | 6693.9588 | 0.2404 | 0.3602 |
| LABB.MX | 20.1804 | 18.9524 | 307.0000 | 6195.3813 | -0.0630 | 0.4490 |
rf = 6.95 / (100) # Treasury Yield Curve Rates 1Yr (2021-12-31)
opt=fn.optimize(mean_lr)
w0, bnds, cons, N = opt[0], opt[1], opt[2], len(mean_lr)
s0_pemv=s0[['GMEXICOB.MX', 'CEMEXCPO.MX', 'PE&OLES.MX', 'CUERVO.MX']]
frames=[w_pemv,s0]
metrics=pd.concat(frames)[['GMEXICOB.MX','CEMEXCPO.MX','PE&OLES.MX','CUERVO.MX']]
metrics
| Symbols | GMEXICOB.MX | CEMEXCPO.MX | PE&OLES.MX | CUERVO.MX |
|---|---|---|---|---|
| Weights | 0.7545 | 0.0725 | 0.0774 | 0.0956 |
| 2020-01-31 00:00:00 | 42.3701 | 7.5950 | 197.2479 | 33.8079 |
# Variance minimization function
def Var(w, cov):
return np.dot(w.T, np.dot(cov, w))
# EMV Minimization function
def Minus_RatioSharpe(w, er, rf, cov):
erp = np.dot(w.T, er)
sp = np.dot(w.T, np.dot(cov, w))**0.5
RS = (erp - rf) / sp
return -RS
pmv = minimize(fun = Var, x0 = w0, args = (cov,), bounds = bnds, constraints = cons, tol = 1e-10)
pemv = minimize(fun = Minus_RatioSharpe, x0 = w0, args = (mean_lr, rf, cov), bounds = bnds, constraints = cons, tol = 1e-10)
#Weights of EMV
w_pemv = pd.DataFrame(np.round(pemv.x.reshape(1, N), 4), columns = log_ret.columns, index = ["Weights"])
w_pemv[w_pemv <= 0.0] = np.nan
w_pemv.dropna(axis = 1, inplace = True)
# Annualized metrics of Passive Investment Portfolio.
Er_pemv = np.dot(pemv.x.T, mean_lr)
s_pemv = (np.dot(pemv.x.T, np.dot(cov, pemv.x)))**0.5
pemv_summary = pd.DataFrame({"Return" : Er_pemv, "Volatility" : s_pemv,
"Sharpe Ratio" : (Er_pemv - rf) / s_pemv}, index = ["EMV Portafolio"])
pemv_summary
| Return | Volatility | Sharpe Ratio | |
|---|---|---|---|
| EMV Portafolio | 0.5564 | 0.3649 | 1.3345 |
plt.style.use('dark_background')
# Minimum Variance Frontier
w = np.linspace(0, 1, 100)
Er_pmv = np.dot(pmv.x, mean_lr/100)
s_pmv = (np.dot(pmv.x.T, np.dot(cov, pmv.x)))**0.5
cov_pmv_pemv = np.dot(pmv.x.T, np.dot(cov, pemv.x))
plt.figure(figsize = (18, 10))
minvar_frontier = pd.DataFrame({"Volatilidad" : ((w*s_pemv)**2 + 2*w*(1-w)*cov_pmv_pemv + ((1-w)*s_pmv)**2)**0.5,
"Rendimiento" : (w*(Er_pemv/100))/100 + (1 - w)*(Er_pemv/100)})
minvar_frontier["Sharpe Ratio"] = (minvar_frontier["Rendimiento"] - rf) / minvar_frontier["Volatilidad"]
plt.scatter(minvar_frontier["Volatilidad"], (minvar_frontier["Rendimiento"])[::-1]*100,
c = minvar_frontier["Sharpe Ratio"], cmap = "coolwarm")
# ACL
sp = np.linspace(0, 0.5)
lac = pd.DataFrame({"Volatilidad" : sp, "Rendimiento" : pemv_summary["Sharpe Ratio"].values[0]*sp + rf})
plt.plot(lac["Volatilidad"], lac["Rendimiento"], "--", color = "white", label = "Línea de asignación de capital")
# Minimum Variance Frontier
plt.plot(s_pemv, (Er_pemv), "*r", ms=16, label = ("EMV:", 'E(r)=',(Er_pemv).round(2),'σ=',s_pemv.round(2)))
# EMV
plt.plot(s_pmv, (Er_pemv/100), "*b", ms=13, color = "dodgerblue",
label = ("Port. min. var.", 'E(r)=',(Er_pemv).round(2),'σ=',s_pmv.round(2)))
# Individual Assets
for i in range(len(stocks_summary2)):
if stocks_summary2.index[i] in w_pemv.columns:
plt.plot(stocks_summary2.iloc[i, 5], stocks_summary2.iloc[i, 4], "*", ms=10, label=('E(r)=',
stocks_summary2.iloc[i, 4].round(2),'σ=',stocks_summary2.iloc[i, 5].round(2)))
plt.text(stocks_summary2.iloc[i, 5] + 0.003, stocks_summary2.iloc[i, 4], stocks_summary2.index[i])
#Style
plt.title("E(r) vs σ for Active Investment EMV from " + str(start.strftime("%Y-%m-%d"))+ ' to ' + str(end.strftime("%Y-%m-%d")),size='17', weight='bold', family="Constantia")
plt.xlabel("Volatility (annualized) $\sigma$",size='15', weight='roman', family="Georgia", color='r')
plt.ylabel("Expected Return (annualized) $E[r]$",size='15', weight='roman', family="Georgia", color='g')
plt.grid(True)
plt.legend(loc = "best")
C:\Users\Esteban\AppData\Local\Temp\ipykernel_49884\3011666208.py:26: UserWarning: color is redundantly defined by the 'color' keyword argument and the fmt string "*b" (-> color='b'). The keyword argument will take precedence.
<matplotlib.legend.Legend at 0x19e4257dc10>
#Dates
start = datetime.datetime(2021,1,31) #Portfolio conformation.
end = datetime.datetime(2022,7,29) #Portfolio EMV maximization end date.
#Daily Adj. closes df
df3 = pdr.DataReader(tickers_ap, 'yahoo',start,end)["Adj Close"] #Adj. closes download
# Mean, Std, and Covariance from returns.
returns3 = df3.pct_change().fillna(0) #NAs filled w/ 0s to preserve daily returns for all rows (days) in every column (ticker)
mean_ret3 = returns3.mean() * 252
cov3 = returns.cov() * 252
stocks_summary3 = pd.DataFrame({"Rendimiento" : mean_ret3, "Volatilidad" : returns3.std()*np.sqrt(252)})
stocks_summary3
| Rendimiento | Volatilidad | |
|---|---|---|
| Symbols | ||
| AMXL.MX | 0.2729 | 0.2273 |
| FEMSAUBD.MX | -0.0073 | 0.2269 |
| GFNORTEO.MX | 0.2042 | 0.3631 |
| WALMEX.MX | 0.1852 | 0.2683 |
| GMEXICOB.MX | 0.0561 | 0.3861 |
| CEMEXCPO.MX | -0.1998 | 0.3985 |
| TLEVISACPO.MX | 0.0881 | 0.4008 |
| GAPB.MX | 0.2717 | 0.2960 |
| ELEKTRA.MX | -0.0804 | 0.1761 |
| ASURB.MX | 0.1678 | 0.2652 |
| KIMBERA.MX | -0.0293 | 0.2759 |
| BIMBOA.MX | 0.4748 | 0.3484 |
| OMAB.MX | 0.1556 | 0.2751 |
| AC.MX | 0.3396 | 0.2169 |
| GFINBURO.MX | 0.4970 | 0.2986 |
| PINFRA.MX | 0.0089 | 0.2157 |
| GRUMAB.MX | 0.1246 | 0.2455 |
| ORBIA.MX | 0.0463 | 0.2650 |
| ALFAA.MX | 0.1437 | 0.2815 |
| GCARSOA1.MX | 0.3614 | 0.3600 |
| PE&OLES.MX | -0.2511 | 0.3599 |
| ALSEA.MX | 0.3977 | 0.3340 |
| BBAJIOO.MX | 0.5850 | 0.3111 |
| MEGACPO.MX | -0.2448 | 0.2361 |
| LIVEPOLC-1.MX | 0.2903 | 0.2749 |
| BOLSAA.MX | -0.0406 | 0.2615 |
| CUERVO.MX | 0.0622 | 0.2716 |
| LABB.MX | 0.0317 | 0.2913 |
pd.set_option('display.float_format', lambda x: '%.6f' % x)
a_cumsum=returns3.iloc[returns3.cumprod().reset_index().groupby(returns3.index.to_period('M'))['Date'].idxmax()]+1
BS=a_cumsum.apply(lambda x: ['SELL' if y <= .95 else "BUY" if y>=1.05 else 'HOLD' if y > .95 and y<1.05 else y for y in x])
BS = BS.style.applymap(lambda x: 'color: red' if x == 'SELL' else 'color: green' if x == 'BUY' else 'color: gray')
BS
| Symbols | AMXL.MX | FEMSAUBD.MX | GFNORTEO.MX | WALMEX.MX | GMEXICOB.MX | CEMEXCPO.MX | TLEVISACPO.MX | GAPB.MX | ELEKTRA.MX | ASURB.MX | KIMBERA.MX | BIMBOA.MX | OMAB.MX | AC.MX | GFINBURO.MX | PINFRA.MX | GRUMAB.MX | ORBIA.MX | ALFAA.MX | GCARSOA1.MX | PE&OLES.MX | ALSEA.MX | BBAJIOO.MX | MEGACPO.MX | LIVEPOLC-1.MX | BOLSAA.MX | CUERVO.MX | LABB.MX |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Date | ||||||||||||||||||||||||||||
| 2021-02-26 00:00:00 | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | BUY | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | BUY | HOLD |
| 2021-03-31 00:00:00 | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | SELL | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD |
| 2021-04-30 00:00:00 | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD |
| 2021-05-31 00:00:00 | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD |
| 2021-06-30 00:00:00 | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD |
| 2021-07-30 00:00:00 | HOLD | HOLD | HOLD | HOLD | SELL | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD |
| 2021-08-31 00:00:00 | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | BUY | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | BUY | HOLD |
| 2021-09-30 00:00:00 | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD |
| 2021-10-29 00:00:00 | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | BUY | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | SELL | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD |
| 2021-11-30 00:00:00 | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | BUY | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | BUY | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD |
| 2021-12-31 00:00:00 | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD |
| 2022-01-31 00:00:00 | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | BUY | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | BUY | HOLD |
| 2022-02-28 00:00:00 | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD |
| 2022-03-31 00:00:00 | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD |
| 2022-04-29 00:00:00 | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | BUY | HOLD |
| 2022-05-31 00:00:00 | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | BUY | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | BUY | SELL | HOLD | HOLD |
| 2022-06-30 00:00:00 | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | SELL | HOLD | BUY | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD |
| 2022-07-29 00:00:00 | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD | HOLD |
# Annualized metrics of Passive Investment Portfolio.
Er_pemv = np.dot(pemv.x.T, mean_lr)
s_pemv = (np.dot(pemv.x.T, np.dot(cov, pemv.x)))**0.5
pemv_summary = pd.DataFrame({"Return" : Er_pemv, "Volatility" : s_pemv,
"Sharpe Ratio" : (Er_pemv - rf) / s_pemv}, index = ["EMV Portafolio"])
pemv_summary
| Return | Volatility | Sharpe Ratio | |
|---|---|---|---|
| EMV Portafolio | 0.556439 | 0.364886 | 1.334497 |
pas_s =(((W*stocks_summary.Volatility).sum()*np.sqrt(252))/np.sqrt(df.shape[0]))
pas_r = df_pasiva['Accumulated Returns'][-1]-1
# Annualized metrics of EMV.
pemv_summary = pd.DataFrame({"Return" : pas_r, "Volatility" : pas_s,
"Sharpe Ratio" : (pas_r - rf) / pas_s}, index = ["Passive Portfolio"])
pemv_summary
| Return | Volatility | Sharpe Ratio | |
|---|---|---|---|
| Passive Portfolio | 0.280047 | 0.211970 | 0.993284 |
df_activa=log_ret[['GMEXICOB.MX', 'CEMEXCPO.MX', 'PE&OLES.MX', 'CUERVO.MX']]*w_pemv.values.flatten()*capital
df_activa["Capital"] = df_activa.sum(axis=1)
df_activa["Capital"][0] = capital*com+capital
df_activa["Capital"]=df_activa["Capital"].cumsum()
df_activa["Portfolio Returns"] = df_activa["Capital"].pct_change()
df_activa["Portfolio Returns"][0] = (capital*com)/capital #Charged on investment day (0).
df_activa["Accumulated Returns"] = (df_activa["Portfolio Returns"] + 1).cumprod()
df_activa.index.name="timestamp"
df_activa.round(6)
df_activa.head()
| Symbols | GMEXICOB.MX | CEMEXCPO.MX | PE&OLES.MX | CUERVO.MX | Capital | Portfolio Returns | Accumulated Returns |
|---|---|---|---|---|---|---|---|
| timestamp | |||||||
| 2020-01-31 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 998750.000000 | -0.001250 | 0.998750 |
| 2020-02-04 | 55946.604781 | 3266.321705 | 1009.232111 | 2753.983238 | 1061726.141835 | 0.063055 | 1.061726 |
| 2020-02-05 | -10536.861661 | -1801.623422 | -1461.599087 | -239.825911 | 1047686.231754 | -0.013224 | 1.047686 |
| 2020-02-06 | -13273.371962 | 0.000000 | -1244.790184 | -3229.034295 | 1029939.035313 | -0.016939 | 1.029939 |
| 2020-02-07 | -8106.919641 | 373.230842 | 56.108769 | -2290.271294 | 1019971.183990 | -0.009678 | 1.019971 |
df_activa.tail()
| Symbols | GMEXICOB.MX | CEMEXCPO.MX | PE&OLES.MX | CUERVO.MX | Capital | Portfolio Returns | Accumulated Returns |
|---|---|---|---|---|---|---|---|
| timestamp | |||||||
| 2021-01-25 | 17035.729631 | 526.850194 | 107.703236 | -3011.894099 | 1604417.870348 | 0.009221 | 1.604418 |
| 2021-01-26 | -11618.634506 | -292.222384 | 1261.561923 | -950.854183 | 1592817.721198 | -0.007230 | 1.592818 |
| 2021-01-27 | -914.000738 | -3233.400976 | -5496.802086 | -4049.248743 | 1579124.268655 | -0.008597 | 1.579124 |
| 2021-01-28 | 1079.960737 | 1993.044642 | 340.280353 | -2863.578483 | 1579673.975903 | 0.000348 | 1.579674 |
| 2021-01-29 | -25670.446525 | -2484.571472 | 1487.773978 | -21.867168 | 1552984.864716 | -0.016895 | 1.552985 |
vs.df_pasiva(df_activa)
| Symbols | Capital | Portfolio Returns | Accumulated Returns |
|---|---|---|---|
| timestamp | |||
| 2020-01-31 | 998750.000000 | -0.001250 | 0.998750 |
| 2020-02-28 | 903578.287129 | 0.021652 | 0.903578 |
| 2020-03-31 | 844520.937752 | 0.080129 | 0.844521 |
| 2020-04-30 | 1004274.235493 | -0.007500 | 1.004274 |
| 2020-05-29 | 966343.565545 | -0.022892 | 0.966344 |
| 2020-06-30 | 1093862.975148 | 0.009924 | 1.093863 |
| 2020-07-31 | 1163432.563285 | -0.003492 | 1.163433 |
| 2020-08-31 | 1205868.311979 | -0.004944 | 1.205868 |
| 2020-09-30 | 1196047.678058 | 0.020156 | 1.196048 |
| 2020-10-30 | 1245464.069608 | -0.003294 | 1.245464 |
| 2020-11-30 | 1404143.313426 | 0.013732 | 1.404143 |
| 2020-12-31 | 1530437.270727 | -0.014844 | 1.530437 |
| 2021-01-29 | 1552984.864716 | -0.016895 | 1.552985 |
According to the metrics and the behavior of the portfolios it can be concluded that an actively managed portfolio has a much bigger expected return but has in fact a higher volatility which is to be expected but even in times of recession it could very well be worth the risks with a higher sharpe ratio as a measure of risk-reward relation. The theory backed up with this paper confirms that it should be opt for risk management rather than passive investment strategies even when drawbacks are expected in the markets.
Active vs. passive investing — the great investment debate. (2022). Retrieved 8 September 2022, from https://www.rathbones.com/sites/rathbones.com/files/literature/pdfs/rathbones_active_vs_passive_investing_james_pettit_investment_report_full_website.pdf
Grupo BMV - Tipos de Índices. (2022). Retrieved 8 September 2022, from https://www.bmv.com.mx/es/Grupo_BMV/Tipos_de_indices
iShares NAFTRAC | NAFTRAC. (2022). Retrieved 8 September 2022, from https://www.blackrock.com/mx/intermediarios/productos/251895/ishares-naftrac-fund
Villalobos, O, 2021. Python Project Template. https://github.com/OmarVillalobos/python-project.